#include <iostream>
#include <unistd.h>
#include <cassert>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>

using namespace std;

// ldd mythread
// ls /lib64/libpthread.*

// 当成结构体来使用
class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};

class ThreadReturn
{
public:
    int exit_code;
    int exit_result;
};

// 1. start_routine,现在是被10个线程执行的， 这个函数现在是重入状态
// 2. 该函数是可重入函数吗？ 是的！
// 3. 在函数内定义的变量，都叫做局部变量，具有临时性 -- 进入依旧适用 -- 在多线程情况下，也没问题 -- 起始每一个线程都有自己独立的栈结构！
void *start_routine(void *args) // 指针也要拷贝，把地址拷贝进来
{
    // 线程的健壮性问题 --> 一个线程如果出现了异常，会影响其他线程吗？会的(健壮性或鲁棒性较差)
    // 为什么？ 进程信号，信号是整体打给进程的！ 进程资源被回收了，线程就没有资源可以使用了
    // string 内部重载了const char* 的类型
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的进行强制类型转换
    int cnt = 10;
    // pthread_exit(nullptr);
    // exit(0); // 不能用exit来终止线程，因为它是用来终止进程的！ 任何一个执行流调用exit都会让整个进程退出
    while (cnt)
    {
        sleep(1);
        cout << "new thead create success, name : " << td->namebuffer << "cnt : " << cnt-- << endl;
        // sleep(1);
        //  int *p = nullptr;
        //  *p = 0;// 想在0号地址处，连续写4个字节的0
    }

    // 线程如何终止？
    // delete td;
    // pthread_exit(nullptr);
    // return nullptr; // 线程函数结束， return的时候，线程就算终止了
    // return (void*)td->number; // warning -> int转void*
    // number写到void*中
    // pthread_exit((void*)td->number);
    ThreadReturn *rt = new ThreadReturn();
    rt->exit_code = 1;
    rt->exit_result = 100;

    return (void *)rt; // 不能 ThreadReturn rt，因为这是在栈上开辟的
}

int main()
{
    // 1.我想创建一批线程
    vector<ThreadData *> threads;
#define NUM 10
    for (int i = 0; i < NUM; ++i)
    {
        // pthread_t tid;
        // char namebuffer[64];

        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s%d", "thread", i);
        // pthread_create(&tid, nullptr, start_routine, (void *)"thread one");
        pthread_create(&td->tid, nullptr, start_routine, td); // 这里传的是缓冲区的起始地址
        // 创建的新线程谁先运行呢？不确定！ 所有如果没有sleep(1)就会导致buffer缓冲区数据被覆盖
        threads.push_back(td);
        // sleep(1);
    }

    for (const auto &iter : threads)
    {
        cout << "create thread: " << iter->namebuffer << " : " << iter->tid << " sucesses, number: " << iter->number << endl;
    }
    // while (true)
    // {
    //     cout << "new thead create success, name : main thread" << endl;
    //     sleep(1);
    // }

    // 线程可以被cancel取消的！ 注意：线程要被取消，前提是这个线程已经跑起来了
    // 线程被取消，退出码-1
    PTHREAD_CANCELED; // -1
    sleep(5);
    for(int i = 0;i < threads.size() / 2;i++)// 线程取消成功，立马join
    {
        pthread_cancel(threads[i]->tid);
        cout << "pthread_cancel : " << threads[i]->namebuffer << " success" << endl;
    }

    for (const auto &iter : threads)
    {
        void* ret = nullptr;// 注意这里是void*
        // ThreadReturn *rt = nullptr;
        // 为什么，没有退出信号？ 线程出异常，收到信号，整个进程都会退出！
        // pthread_join:默认就认为函数会调用成功！不考虑异常问题，异常问题是你进程该考虑的问题！
        int n = pthread_join(iter->tid, &ret); // void** retp; *retp = return (void*)td->number
        assert(n == 0);
        cout << "join: " << iter->namebuffer << " success, number : " << (long long)ret << endl;// 如果先delete了就会段错误
        // cout << "join: " << iter->namebuffer << " success, code : " << rt->exit_code << " ,exit_rrsult: " << rt->exit_result << endl;
        delete iter;
    }

    cout << "main thread quit " << endl;

    // pthread_t id;
    // // int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); const pthread_attr_t *attr:没必要设置的
    // pthread_create(&id,nullptr,start_routine,(void*)"thread one");
    // while(true)
    // {
    //     cout << "new thead create success, name : main thread"  << endl;
    //     sleep(1);
    // }
    return 0;
}

////////////////////////////////调用接口/////////////////////////////////

// void pthread_exit(void *retval); 哪个线程要退出，就调用
// void *retval：退出码

// void *start_routine(void *args):这里的返回值也是void*
// int pthread_join(pthread_t thread, void **retval);**retval：所以是输出型参数，能拿到返回值结果
// 本质：是冲库中获取执行线程的退出结果

// int pthread_cancel(pthread_t thread); 向线程发起取消请求

///////////////////////////////////////////////////////////////////////////

// 线程也是要被等待的！如果不等待，会造成类似将僵尸进程的问题 -- 内存泄漏
// 线程必须也要被等待：
// 1.获取新线程的退出信息 --> 可以不关心退出信息
// 2.会手新线程对应的PCB等内核资源，防止内存泄漏 -- 暂时无法查看！

/////////////////////////////再谈谈pthead线程库//////////////////////////////

// 任何语言，再linux中如果要实现多线程，必定要用pthrad库
// 如何看到C++11中的多线程呢？？ C++11 的多线程，再linux环境中，本质是对pthread库的封装！！